package com.ctg.behavior.calc.impala.calculator;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import com.ctg.behavior.calc.common.CtSQLParam;
import com.ctg.behavior.calc.impala.CtCalculator;
import com.ctg.behavior.calc.impala.builder.event.CtEventCalcResultBuilder;
import com.ctg.behavior.calc.impala.builder.event.CtEventMeasureReportBuilder;
import com.ctg.behavior.calc.impala.engine.ImpalaSQLEngine;
import com.ctg.behavior.calc.impala.report.event.CtCalcEventMeasureReport;
import com.ctg.behavior.calc.impala.transfer.event.CtEventMeasureTransfer;
import com.ctg.behavior.calc.impala.utils.CtCalculatorUtils;
import com.ctg.behavior.client.impala.common.CtQueryResult;
import com.ctg.behavior.common.calc.CtCalcBody;
import com.ctg.behavior.common.calc.CtCalcResult;
import com.ctg.behavior.common.consts.CtCalcTaskConsts;
import com.ctg.behavior.common.event.CtEventCalcBody;
import com.ctg.behavior.common.event.CtEventCalcData;
import com.ctg.behavior.common.event.CtEventCalcResult;
import com.ctg.behavior.utils.CtDateUtils;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
public class CtEventCalculator implements CtCalculator {

	@Autowired
	private CtEventMeasureReportBuilder measureReportBuilder;
	@Autowired
	private CtEventCalcResultBuilder eventCalcResultBuilder;
	@Autowired
	private CtEventMeasureTransfer eventMeasureTransfer;
	@Autowired
	private ImpalaSQLEngine sqlEngine;

	/****************************************************************
	 * @apiNote: 1.事件计算是按measure执行(一个measure对应一个独立执行体)
	 * @apiNote: 2.每个SQL的执行结果合并到CtEventCalcResult中
	 */
	@Override
	public CtCalcResult doCalculator(CtCalcBody calcBody) {
		CtEventCalcResult calcResult = new CtEventCalcResult();
		if (!(calcBody instanceof CtEventCalcBody)) {
			log.error("calcBody={}", calcBody.getClass());
			calcResult.setSuccess(false);
			return calcResult;
		}
		CtEventCalcData calcData = new CtEventCalcData();
		calcResult.setValue(calcData);

		log.info("doBuilder-start: {}", CtDateUtils.getCurrentDateSSS());
		CtEventCalcBody eventCalcBody = (CtEventCalcBody) calcBody;
		// 1. 从CtEventCalcBody组建CtCalcEventMeasureReport
		List<CtCalcEventMeasureReport> measureReports = new ArrayList<>();
		measureReports = measureReportBuilder.doBuilder(eventCalcBody);
		log.info("doBuilder-end: {}", CtDateUtils.getCurrentDateSSS());
		// 2. 初始化ResultBuilder
		eventCalcResultBuilder.resetResultBuilderTheadLocal();
		// 3. 分步计算，并合并每一步的计算结果
		log.info("time - start: {}", CtDateUtils.getCurrentDateSSS());
		for (CtCalcEventMeasureReport oneReport : measureReports) {
			log.info("one-time-start: {}", CtDateUtils.getCurrentDateSSS());
			// 2. 转换成measure对应的SQL
			log.info("one-report={}", JSON.toJSONString(oneReport));
			CtSQLParam sqlParam = new CtSQLParam();
			String measureSql = eventMeasureTransfer.doTransfer(oneReport, sqlParam);
			log.info("one-measureSql={}", measureSql);

			String queryType = CtCalcTaskConsts.TASK_TYPE_SEGMENTATION;
			queryType = queryType + "@" + oneReport.getEventId() + "@" + oneReport.getCaclDate().getFromDate();
			CtQueryResult queryResult = sqlEngine.doQuery(queryType, measureSql);
			log.info("one-queryResult={}", JSON.toJSONString(queryResult));

			CtCalculatorUtils.fillCalcResult(calcResult, queryResult);
			if (!calcResult.getSuccess()) {
				log.error(queryResult.getCode());
				break;
			}
			
//			// TEMP: 初始化时间坐标
//			{
//				for(CtCalcDate calcDate : oneReport.getCalcDateSeries()) {
//				}
//			}

			// TEMP: 组建SeriesDay有序Map
			LinkedHashMap<String, List<LinkedHashMap<String, Object>>> seriesDaysMap = null;
			seriesDaysMap = new LinkedHashMap<>();
			for (LinkedHashMap<String, Object> oneRecord : queryResult.getRows()) {
				String seriesDay = String.valueOf(oneRecord.get("byTime"));
				List<LinkedHashMap<String, Object>> series = seriesDaysMap.get(seriesDay);
				if (null == series) {
					series = new ArrayList<LinkedHashMap<String, Object>>();
					seriesDaysMap.put(seriesDay, series);
				}
				series.add(oneRecord);
			}
			Set<Entry<String, List<LinkedHashMap<String, Object>>>> entries = seriesDaysMap.entrySet();
			for (Entry<String, List<LinkedHashMap<String, Object>>> entry : entries) {
				// 3. sqlEngine的结果转换并添加到CtEventCalcResult
				String seriesDay = String.valueOf(entry.getKey());
				calcData = eventCalcResultBuilder.doBuilder(seriesDay, calcData, entry.getValue(), oneReport, eventCalcBody.getMeasures().size());
			}
			log.info("one-result={}", JSON.toJSONString(calcData));
			log.info("one-time-end: {}", CtDateUtils.getCurrentDateSSS());
		}
		log.info("time - end: {}", CtDateUtils.getCurrentDateSSS());
		return calcResult;
	}

}
